package relu.fbs.xt;

import java.text.DecimalFormat;
import java.util.*;

import relu.fbs.BadDataException;
import relu.fbs.FarmData;

import jfm.model.Types.CropType;

public class FBSCropData {

	public final CropType cropType;
	private boolean isBad = false;
	public void flagBadCrop(){isBad=true;};
	public boolean isBad(){return isBad;};
	public Double getValue(FBSCDatum dat) {
		if ( dat.isIntensive){
			return data.get(dat).avValue();
		} else {
			return data.get(dat).sumValue();
		}
	}
	public enum FBSCDatum {
		AREA ("area"),
		MAREA("marea"), // Multiple cropping area ?
		AREASA ("areasa"),
		PRODUCTION("production"),
		PRODUCTIONSA("productionsa"),
		TREMAIN("tremain"),
		VREMAIN("vremain"),
		TREMAINSA("tremainsa"),
		VREMAINSA("vremainsa"),
		TSOLD("tsold"),
		TSOLDSA("tsoldsa"),
		VSOLD("vsold"),
		VSOLDSA("vsoldsa"),
		TFEED("tfeed"),
		VFEED("vfeed"),
		TONFARMCONS("tonfarmcons"),
		VONFARMCONS("vonfarmcons"),
		YIELD("yield",true),
		YIELDSA("yieldsa",true),
		AREAENTITLEMENT("areaentitlement"),
		AREAENTITLEMENTSA("areaentitlementsa"),
		AREAPAYMENT("areapayment"),
		EO("eo"),
		EOSA("eosa");
		public final boolean isIntensive;
		
		public final String RName;
		private FBSCDatum(String rn){
			RName=rn;
			isIntensive=false;
		};
		private FBSCDatum(String rn,boolean iI){
			RName=rn;
			isIntensive=iI;
		}
	}
	
	private static Map<FBSCDatum,FBSCDatum> totalToSAMap = new HashMap<FBSCDatum,FBSCDatum>();
	static {
		totalToSAMap.put(FBSCDatum.AREA, FBSCDatum.AREASA);
		totalToSAMap.put(FBSCDatum.PRODUCTION, FBSCDatum.PRODUCTIONSA);
		totalToSAMap.put(FBSCDatum.TREMAIN, FBSCDatum.TREMAINSA);
		totalToSAMap.put(FBSCDatum.VREMAIN, FBSCDatum.VREMAINSA);
		totalToSAMap.put(FBSCDatum.TSOLD, FBSCDatum.TSOLDSA);
		totalToSAMap.put(FBSCDatum.VSOLD, FBSCDatum.VSOLDSA);
		totalToSAMap.put(FBSCDatum.YIELD, FBSCDatum.YIELDSA);
		totalToSAMap.put(FBSCDatum.AREAENTITLEMENT, FBSCDatum.AREAENTITLEMENTSA);
		totalToSAMap.put(FBSCDatum.EO, FBSCDatum.EOSA);
	}
	/*
	public void consolidate(){		
		// To avoid double counting of setaside and normal data we subtract setaside from the total (if non-zero)
		for ( Map.Entry<FBSCDatum, FBSCDatum> tsaMap :totalToSAMap.entrySet()){
			
			FBSCDatum totD = tsaMap.getKey();
			FBSCDatum saD = tsaMap.getValue();
			FBSPost2000DataValue totV=data.get(totD);
			FBSPost2000DataValue saV=data.get(saD);
			if ( totV.autoValue() > saV.autoValue()){
				data.put(totD, new FBSPost2000DataValue(totV.autoValue()-saV.autoValue(),totD));
			}
		}
		
	}
	*/
	private final LinkedHashMap<FBSCDatum,FBSPost2000DataValue> data=new LinkedHashMap<FBSCDatum,FBSPost2000DataValue>();
	

	public FBSCropData(CropType ct){
		cropType=ct;
	}
	
	private boolean duplicateIsSetAsideGeneric(FBSPost2000DataPoint pnt,FBSPost2000DataPoint oldpnt){
		boolean[] matchStatus=pnt.match(oldpnt);
		for ( int i=0;i<3;i++){ // First three must match
			if (!matchStatus[i]){
				return false;
			}
		}
		if (pnt.ctype == 10 && oldpnt.ctype==10){
			if ( pnt.col==22 && data.containsKey(FBSCDatum.AREASA)){
				return true;
			}
		}
		return false;
	}
	private boolean duplicateIsSameCropGroup(FBSPost2000DataPoint pnt,FBSPost2000DataPoint oldpnt){
		CropType oldct=FarmData.fbsCodeToCropType.get(oldpnt.row);
		CropType newct=FarmData.fbsCodeToCropType.get(pnt.row);
		if ( oldct!=newct){
			return false;
		}
		return true;
	}
	
	private enum DuplicateDatumStatus {
		OLDOK, NEEDSNEW, ADD,ERROR;
	}
	private DuplicateDatumStatus getStatusOfDuplicate(FBSCDatum key,FBSPost2000DataPoint pnt){
		FBSPost2000DataPoint oldpnt=data.get(key).ident;
		if ( duplicateIsSetAsideGeneric(pnt,oldpnt)){
			return DuplicateDatumStatus.OLDOK;
		} 
		if ( duplicateIsSameCropGroup(pnt,oldpnt)){
			return DuplicateDatumStatus.ADD;
		}
		
		return DuplicateDatumStatus.ERROR;

	}
	
	public void setDatum(FBSCDatum key,Double v,FBSPost2000DataPoint pnt) throws BadDataException {
		if (data.containsKey(key)){
			switch(getStatusOfDuplicate(key,pnt)){
			case OLDOK:
				break;
			case NEEDSNEW:
				data.put(key, new FBSPost2000DataValue(pnt,v,key));
				break;
			case ADD:
				data.get(key).add(v);
				break;
			case ERROR:
				throw new BadDataException("Can't add duplicate values for Crop data. Already has value "+data.get(key)+" for "+key+" on crop "+cropType+"\n");
			}
		} else {
			data.put(key, new FBSPost2000DataValue(pnt,v,key));
		}
	}
	

	public int setValues(int i,String[] vals){
		for (FBSCDatum label:FBSCDatum.values()){
			data.put(label, new FBSPost2000DataValue(Double.parseDouble(vals[i]),label));
			i++;
		}
		return i;
	}

	public static String allToCSVCropLabels(CropType ct){
		StringBuffer buff=new StringBuffer();
		for ( FBSCDatum label:FBSCDatum.values()){
			buff.append(ct+"."+label.RName+",");
		}
		buff.deleteCharAt(buff.length()-1); // Delete last comma
		return buff.toString();
	}
	
	public static String allToCSVLabels(){
		StringBuffer buff=new StringBuffer();
		for ( FBSCDatum label:FBSCDatum.values()){
			buff.append(label.RName+" ");
		}
		buff.deleteCharAt(buff.length()-1); // Delete last comma
		return buff.toString();
	}

	public  String allToCSV(DecimalFormat fmt){
		StringBuffer buff=new StringBuffer();

		for (FBSCDatum label:FBSCDatum.values()){
			if ( data.containsKey(label)){
				buff.append(fmt.format(this.getValue(label))+",");
			} else {
				buff.append(0.0+",");
			}
		}
		buff.deleteCharAt(buff.length()-1); // Delete last comma
		return buff.toString();
	}
	
}
